package videosearch;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

// This GUI class is the main gui of the application. it holds all the gui
// objects and handles many of the update functions
public class Gui extends JFrame {
    private static final long serialVersionUID = 1386236896535976072L;
    
    static final boolean mode = false; // False for input, True for matching
    static final String databaseFileName = "db.csv"; // Database file
    static final int Width = 352; // Width of input video
    static final int Height = 288; // Height of input video
    
    String matchFileName;
    String queryFileName;
    
    private HashMap<String, Integer> matchedVideosMatchPoint;
    private HashMap<String, Pair> pairMatches;
    
    Dimension dimension;
    int queryPosition;
    int matchPosition;
    ArrayList<BufferedImage> query;
    ArrayList<BufferedImage> match;
    
    //GUI Half Panels
    private JPanel leftHalf;
    private JPanel rightHalf;
    
    // Query Info
    private JLabel queryPathLabel;
    private JTextField queryPath;
    private JButton matchQuery;
    private JButton playMatchQuery;
    
    // Match Info
    private JLabel matchedVideosLabel;
    private JList<String> matchedVideos;
    private JScrollPane matchedVideosScroller;
    private ChartPanel matchChart;
    
    // Video Scrubbing
    private JSlider queryScrubber;
    private JSlider matchScrubber;
    
    // Video Panels
    private JPanel queryPanel;
    private JPanel matchPanel;
    
    //Icon
    private ImageIcon queryIcon;
    private ImageIcon matchIcon;
    private JLabel matchLabel;
    private JLabel queryLabel;
    
    // Video Navigation Buttons
    private JButton queryPlayButton;
    private JButton queryPauseButton;
    private JButton queryStopButton;
    private JButton matchPlayButton;
    private JButton matchPauseButton;
    private JButton matchStopButton;
    private PlaySound matchSound;
    private PlaySound querySound;
    private Timer matchUpdateTimer;
    private Timer queryUpdateTimer;
    private String matchAudioFile;
    private String queryAudioFile;

    // Constructor calls init on all the components to place layouts, and shows
    // the gui
    public Gui() {
        initComponents();
    }

    // Constructor for a query file as input, calls the query media creator and
    // inits and shows the GUI components
    public Gui(String queryFileName, String queryAudioFileName) {
        getQueryMedia(queryFileName, queryAudioFileName);
        initComponents();
    }

    // starts the query video ingestor and audio player
    public void getQueryMedia(String queryFileName, String queryAudioFileName) {
        this.queryFileName = queryFileName;

        query = new ArrayList<>();

        // create an ingestor for the query video data
        RGBIngestor rgb = new RGBIngestor(queryFileName, query);
        queryAudioFile = queryAudioFileName;

        Thread rgbThread = new Thread(rgb); // create a new thread to go fast
        rgbThread.start();
        try {
            rgbThread.join(); // join the thread in to safely share data space
            rgbThread.interrupt();
        } catch (InterruptedException e) {
            System.out.println("Exception: " + e.getMessage());
        }

    }

    // Sets the matches in the gui, called after we've computed matches
    public void setMatches(ArrayList<Pair> matches) {
        matchedVideosMatchPoint = new HashMap<String, Integer>(matches.size());
        pairMatches = new HashMap<String, Pair>(matches.size());
        String[] matchesList = new String[matches.size()];
        
        // Loop through the matches and create the list of matches in order
        for (int i = 0; i < matches.size(); i++) {
            Pair match = matches.get(i);
            matchesList[i] = String.format("%s (%s%%)", match.fileName, Math.round(100 - ((match.min / 386.78159211627432360648678656591) * 100)));
            matchedVideosMatchPoint.put(match.fileName, match.index);
            pairMatches.put(match.fileName, match);
        }
        matchedVideos.setListData(matchesList);

        // Start with first file
        getMatchMedia(matches.get(0).fileName);
        matchedVideos.setSelectedValue(matchesList[0], true);
        main();
    }

    // Get the matched media file - creates the ingestor and joins the thread
    private void getMatchMedia(String matchFileName) {
        this.matchFileName = matchFileName;
        if (match != null) {
            match.clear();
        }
        match = new ArrayList<>();
        RGBIngestor rgb = new RGBIngestor(matchFileName, match);
        matchAudioFile = matchFileName.replaceFirst(".rgb", ".wav");

        Thread rgbThread = new Thread(rgb); // new thread for streamlining
        rgbThread.start();

        try {
            rgbThread.join(); // join in to share data space
        } catch (InterruptedException e) {
            System.out.println("Exception: " + e.getMessage());
        }
    }

    /**
     * @param args the command line arguments Should get the video file and
     * audio file from cmd line "Database" is represented by flat file hardcoded
     */
    public void main() {
        // instantiate variables
        queryPath.setText(queryFileName);
        setUpNavButtons();
        setUpNavSliders();
        setUpListSelectionListener();
        setUpBestMatchButtons();
        updateChartPanel();
        repaint(); // repaint the gui

        dimension = new Dimension(Width, Height); // create a new dimension
        queryPosition = 0;
        matchPosition = 0;

        // initializes the playSound Object
        matchSound = new PlaySound(matchAudioFile);
        querySound = new PlaySound(queryAudioFile);

        // sets up the sound
        try {
            matchSound.setupStream();
            matchSound.openDataLine();
            querySound.setupStream();
            querySound.openDataLine();
        } catch (PlayWaveException e) {
            e.printStackTrace();
            return;
        }

        // sets the first image
        queryIcon.setImage(query.get(queryPosition));
        queryPanel.repaint();
        updateScrubber(queryScrubber, queryPosition);

        matchIcon.setImage(match.get(matchPosition));
        matchPanel.repaint();
        updateScrubber(matchScrubber, matchPosition);

        // Update Timer handles the updates to the query video panel
        queryUpdateTimer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if (query == null) {
                    return;
                }
                queryIcon.setImage(query.get(queryPosition)); // set the new img
                queryPanel.repaint(); // repaint the panel
                updateScrubber(queryScrubber, queryPosition); // update the bar
                try {
                    querySound.playNextFrame();
                } catch (PlayWaveException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                queryPosition++; // Keep counter of where we are, to loop
                if (queryPosition >= query.size()) {
                    queryUpdateTimer.stop();
                    querySound.closeDataLine();
                }
            }
        });
        queryUpdateTimer.setRepeats(true); // repeat

        // Update Timer handles the updates to the match video panel
        matchUpdateTimer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if (match == null) {
                    return; // error case
                }

                matchIcon.setImage(match.get(matchPosition)); // new image
                matchPanel.repaint(); // repaint gui
                updateScrubber(matchScrubber, matchPosition);
                try {
                    matchSound.playNextFrame();
                } catch (PlayWaveException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                matchPosition++; // Keep counter of where we are, to loop
                if (matchPosition >= match.size()) {
                    matchUpdateTimer.stop();
                    matchSound.closeDataLine();
                }
            }
        });
        matchUpdateTimer.setRepeats(true);

        //Start it up - set the frame to visible
        setVisible(true);
    }

    // Calls stop on all the videos and audio
    private void stopAllVideos() {
        queryUpdateTimer.stop();
        matchUpdateTimer.stop();
        matchSound.closeAudioStreams();
        querySound.closeAudioStreams();
    }

    // Updates the sliders
    private void updateScrubber(JSlider scrubber, int position) {
        if (!scrubber.getValueIsAdjusting()) {
            scrubber.setValue(position);
        }
    }

    // Initializes the components on the gui and creates the layouts
    private void initComponents() {
        leftHalf = new JPanel();
        rightHalf = new JPanel();

        queryPathLabel = new JLabel("Query: ");
        queryPath = new JTextField();

        matchQuery = new JButton();
        playMatchQuery = new JButton();

        matchedVideosLabel = new JLabel("Matched Videos: ");
        matchedVideos = new JList<>();
        matchedVideosScroller = new JScrollPane(matchedVideos);
        matchChart = new ChartPanel(new double[0]);


        matchIcon = new ImageIcon(new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB));
        matchLabel = new JLabel(matchIcon);
        queryIcon = new ImageIcon(new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB));
        queryLabel = new JLabel(queryIcon);

        queryScrubber = new JSlider(JSlider.HORIZONTAL); // TODO Update this
        matchScrubber = new JSlider(JSlider.HORIZONTAL); // TODO Update this

        matchPanel = new JPanel();

        queryPanel = new JPanel();

        queryPlayButton = new JButton();
        queryPauseButton = new JButton();
        queryStopButton = new JButton();
        matchPlayButton = new JButton();
        matchPauseButton = new JButton();
        matchStopButton = new JButton();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        // Query Area Setup
        queryPath.setAutoscrolls(true);
        queryPath.setColumns(20);
        queryPath.setEditable(false);

        // Match Interaction
        matchQuery.setText("Align Best Match");
        playMatchQuery.setText("Play Best Match");

        // Match Area Setup
        matchedVideos.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        matchedVideos.setLayoutOrientation(JList.VERTICAL);
        matchedVideos.setVisibleRowCount(3);

        matchChart.setPreferredSize(new Dimension(352, 40));

        // Query Panel Setup
        queryPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        queryPanel.setPreferredSize(new Dimension(352, 288));
        GroupLayout queryPanelLayout = new GroupLayout(queryPanel);
        queryPanel.setLayout(queryPanelLayout);
        queryPanelLayout.setHorizontalGroup(
                queryPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(queryLabel)
                .addGap(0, 350, Short.MAX_VALUE));
        queryPanelLayout.setVerticalGroup(
                queryPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(queryLabel)
                .addGap(0, 286, Short.MAX_VALUE));

        // Match Panel Setup
        matchPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        matchPanel.setPreferredSize(new Dimension(352, 288));
        GroupLayout matchPanelLayout = new GroupLayout(matchPanel);
        matchPanel.setLayout(matchPanelLayout);

        matchPanelLayout.setHorizontalGroup(
                matchPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(matchLabel)
                .addGap(0, 350, Short.MAX_VALUE));
        matchPanelLayout.setVerticalGroup(
                matchPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(matchLabel)
                .addGap(0, 286, Short.MAX_VALUE));

        // Video Navigation Setup
        queryPlayButton.setText("Play");
        queryPauseButton.setText("Pause");
        queryStopButton.setText("Stop");
        matchPlayButton.setText("Play");
        matchPauseButton.setText("Pause");
        matchStopButton.setText("Stop");

        // Left Half Setup        
        leftHalf.setBorder(BorderFactory/*.createLineBorder(Color.BLACK, 20, false)*/.createEmptyBorder(20, 20, 20, 20));
        leftHalf.setBackground(Color.WHITE);
        leftHalf.setSize(400, 600);
        GroupLayout leftPanelLayout = new GroupLayout(leftHalf);
        leftHalf.setLayout(leftPanelLayout);
        leftPanelLayout.setHorizontalGroup(
                leftPanelLayout.createParallelGroup()
                .addGroup(GroupLayout.Alignment.LEADING, leftPanelLayout.createSequentialGroup()
                .addGap(35, 35, 35)
                .addComponent(queryPathLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(35, 35, 35)
                .addComponent(queryPath, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, leftPanelLayout.createSequentialGroup()
                .addComponent(matchQuery, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(35, 35, 35)
                .addComponent(playMatchQuery, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, leftPanelLayout.createSequentialGroup()
                .addComponent(queryScrubber, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, leftPanelLayout.createSequentialGroup()
                .addComponent(queryPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.LEADING, leftPanelLayout.createSequentialGroup()
                .addGap(101, 101, 101)
                .addComponent(queryPlayButton)
                .addGap(18, 18, 18)
                .addComponent(queryPauseButton)
                .addGap(18, 18, 18)
                .addComponent(queryStopButton)
                .addGap(109, 109, 109)));
        leftPanelLayout.setVerticalGroup(
                leftPanelLayout.createSequentialGroup()
                .addGroup(leftPanelLayout.createParallelGroup()
                .addComponent(queryPathLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addComponent(queryPath, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGap(30, 30, 30)
                .addGroup(leftPanelLayout.createParallelGroup()
                .addComponent(matchQuery, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addComponent(playMatchQuery, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGap(30, 30, 30)
                .addGroup(leftPanelLayout.createParallelGroup()
                .addComponent(queryScrubber, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(leftPanelLayout.createParallelGroup()
                .addComponent(queryPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(leftPanelLayout.createParallelGroup()
                .addComponent(queryPlayButton)
                .addComponent(queryPauseButton)
                .addComponent(queryStopButton)));

        // Right Half Setup
        rightHalf.setBorder(BorderFactory./*createLineBorder(Color.BLACK, 20, false)*/createEmptyBorder(20, 20, 20, 20));
        rightHalf.setBackground(Color.WHITE);
        rightHalf.setSize(400, 600);
        GroupLayout rightPanelLayout = new GroupLayout(rightHalf);
        rightHalf.setLayout(rightPanelLayout);
        rightPanelLayout.setHorizontalGroup(
                rightPanelLayout.createParallelGroup()
                .addGroup(GroupLayout.Alignment.LEADING, rightPanelLayout.createSequentialGroup()
                .addGap(35, 35, 35)
                .addComponent(matchedVideosLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, rightPanelLayout.createSequentialGroup()
                .addGap(35, 35, 35)
                .addComponent(matchedVideosScroller, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, rightPanelLayout.createSequentialGroup()
                .addComponent(matchChart, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, rightPanelLayout.createSequentialGroup()
                .addComponent(matchScrubber, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.CENTER, rightPanelLayout.createSequentialGroup()
                .addComponent(matchPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(GroupLayout.Alignment.LEADING, rightPanelLayout.createSequentialGroup()
                .addGap(101, 101, 101)
                .addComponent(matchPlayButton)
                .addGap(18, 18, 18)
                .addComponent(matchPauseButton)
                .addGap(18, 18, 18)
                .addComponent(matchStopButton)
                .addGap(109, 109, 109)));

        rightPanelLayout.setVerticalGroup(
                rightPanelLayout.createSequentialGroup()
                .addGroup(rightPanelLayout.createParallelGroup()
                .addComponent(matchedVideosLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(rightPanelLayout.createParallelGroup()
                .addComponent(matchedVideosScroller, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(rightPanelLayout.createParallelGroup()
                .addComponent(matchChart, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(rightPanelLayout.createParallelGroup()
                .addComponent(matchScrubber, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGroup(rightPanelLayout.createParallelGroup()
                .addComponent(matchPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(rightPanelLayout.createParallelGroup()
                .addComponent(matchPlayButton)
                .addComponent(matchPauseButton)
                .addComponent(matchStopButton)));

        // Setup the JFrame with the panels created above
        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setBackground(Color.WHITE);
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createSequentialGroup()
                .addComponent(leftHalf)
                .addComponent(rightHalf));
        layout.setVerticalGroup(
                layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
                .addComponent(leftHalf)
                .addComponent(rightHalf));

        pack(); // pack the frame up
        // Lock size
        setResizable(false);
    }

    // Set up the navigation sliders
    private void setUpNavSliders() {
        matchScrubber.setMinimum(0);
        matchScrubber.setMaximum(match.size());
        matchScrubber.addChangeListener(new ChangeListener() {
            private int previousframe = 0;

            // If the state changes, update the gui appropriately
            @Override
            public void stateChanged(ChangeEvent arg0) {
                if (!matchScrubber.getValueIsAdjusting()) {
                    int frame = (int) matchScrubber.getValue();
                    // Logic to find the right frame
                    if (Math.abs(frame - previousframe) > 1) {
                        if (matchUpdateTimer.isRunning()) {
                            matchUpdateTimer.stop();
                            matchPosition = frame;
                            try {
                                matchSound.goToSpecifiedFrame(frame);
                            } catch (PlayWaveException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            matchUpdateTimer.start();
                        } else {
                            matchPosition = frame;
                            try {
                                matchSound.goToSpecifiedFrame(frame);
                            } catch (PlayWaveException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                    previousframe = frame;
                }
            }
        });

        // Do the same stuff below as you would above, they're the same
        queryScrubber.setMinimum(0);
        queryScrubber.setMaximum(query.size());
        queryScrubber.addChangeListener(new ChangeListener() {
            private int previousframe = 0;

            @Override
            public void stateChanged(ChangeEvent arg0) {
                if (!queryScrubber.getValueIsAdjusting()) {
                    int frame = (int) queryScrubber.getValue();
                    if (Math.abs(frame - previousframe) > 1) {
                        if (queryUpdateTimer.isRunning()) {
                            queryUpdateTimer.stop();
                            queryPosition = frame;
                            try {
                                querySound.goToSpecifiedFrame(frame);
                            } catch (PlayWaveException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            queryUpdateTimer.start();
                        } else {
                            queryPosition = frame;
                            try {
                                querySound.goToSpecifiedFrame(frame);
                            } catch (PlayWaveException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                    previousframe = frame;
                }
            }
        });
    }

    // Updates the chart panel if the match video changes
    private void updateChartPanel() {
        ArrayList<Double> data = pairMatches.get(matchFileName).data;
        Object[] res = data.toArray();
        double[] values = new double[data.size()];
        for (int i = 0; i < values.length; i++) {
            values[i] = (double) res[i];
        }
        matchChart.updateChart(values);
    }

    // Sets up the listener for value changes in the slider
    private void setUpListSelectionListener() {
        matchedVideos.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting() == false) {
                    String selection = matchedVideos.getSelectedValue();
                    String fileName = selection.split("\\s")[0];
                    stopAllVideos();
                    // Start with first file
                    getMatchMedia(fileName);

                    main();
                }
            }
        });
    }

    // Sets up the buttons for the matching area, to play, pause, stop
    private void setUpBestMatchButtons() {
        matchQuery.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                queryUpdateTimer.stop(); // stop the timers that update
                matchUpdateTimer.stop();
                queryPosition = 0; // reset because we're stoping
                matchPosition = matchedVideosMatchPoint.get(matchFileName);
                try {
                    querySound.goToSpecifiedFrame(0);
                    matchSound.goToSpecifiedFrame(matchPosition);
                } catch (PlayWaveException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                // set the first image and repaint in both windows
                queryIcon.setImage(query.get(queryPosition));
                queryPanel.repaint();
                updateScrubber(queryScrubber, queryPosition);

                matchIcon.setImage(match.get(matchPosition));
                matchPanel.repaint();
                updateScrubber(matchScrubber, matchPosition);
            }
        });

        // Add the new action listener for the clicks
        playMatchQuery.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                matchQuery.doClick();
                queryUpdateTimer.start();
                matchUpdateTimer.start();
            }
        });
    }

    // set up navigation within the video buttons
    private void setUpNavButtons() {
        // start button for the query play
        queryPlayButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                queryUpdateTimer.start();
                querySound.openDataLine();
            }
        });
        // pause button
        queryPauseButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                queryUpdateTimer.stop();
                querySound.closeDataLine();
            }
        });
        // stop button
        queryStopButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                queryPosition = 0;
                try {
                    querySound.resetStreamToBeginning();
                } catch (PlayWaveException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                queryUpdateTimer.stop();
                querySound.closeDataLine();
            }
        });

        // play button in the match area
        matchPlayButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                matchUpdateTimer.start();
                querySound.openDataLine();
            }
        });
        // pause button
        matchPauseButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                matchUpdateTimer.stop();
                matchSound.closeDataLine();
            }
        });
        // stop button
        matchStopButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                matchPosition = 0;
                try {
                    matchSound.resetStreamToBeginning();
                } catch (PlayWaveException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                matchUpdateTimer.stop();
                matchSound.closeDataLine();
            }
        });
    }
}
